/**
 * File: ReadWrapper.java
 * Created by: mhaimel
 * Created on: Mar 15, 2010
 * CVS:  $Id: ReadWrapper.java 1.0 Mar 15, 2010 12:02:54 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.model.graph.curtain;

import java.lang.reflect.Array;
import java.util.concurrent.atomic.AtomicReferenceArray;

/**
 * @author mhaimel
 *
 */
public class ReadWrapper {

	private final Long id;
	private final AtomicReferenceArray<CategoryReadInfo> infoArr;
	
	public ReadWrapper(Long id, Integer categories) {
		this.infoArr = new AtomicReferenceArray<CategoryReadInfo>(categories);
		this.id = id;
	}
	
	public Long getId() {
		return id;
	}
	
	public Integer getCategories(){
		return this.infoArr.length();
	}
	
	public boolean hasAnyInfo(){
		int size = this.infoArr.length();
		for(int i = 0; i < size; ++i){
			if(this.infoArr.get(i) != null){
				return true;
			}
		}
		return false;
	}
	
	public boolean hasInfo(Integer cat){
		return this.infoArr.get(cat) != null;
	}
	
	public CategoryReadInfo getInfo(Integer cat){
		return this.infoArr.get(cat);
	}
	
	public void forceSetCategoryReadInfo(Integer cat, CategoryReadInfo info){
		this.infoArr.set(cat, info);
	}
	
	public CategoryReadInfo setOrGetEmptyCategoryReadInfo(Integer cat, CategoryReadInfo info){
		if(this.infoArr.compareAndSet(cat, null, info)){
			return info;
		} else {
			return this.infoArr.get(cat); // Not empty any more
		}
	}

	public void addRead(Integer cat, int gap, double weight) {
		CategoryReadInfo info = infoArr.get(cat);
		if(null == info){
			info = setOrGetEmptyCategoryReadInfo(cat, new CategoryReadInfo(cat));
		}
		info.addRead(gap, weight);		
	}
	
	public void addRead(Integer cat,double weight) {
		CategoryReadInfo info = infoArr.get(cat);
		if(null == info){
			info = setOrGetEmptyCategoryReadInfo(cat, new CategoryReadInfo(cat));
		}
		info.addRead(weight);		
	}

	public Integer[] arrayOfMultiplicity() {
		Integer cat = getCategories();
		Integer[] arr = (Integer[]) Array.newInstance(Integer.class, cat);
		for(int i = 0; i < cat; i++ ){
			arr[i] = this.hasInfo(i)?this.getInfo(i).getMultiplicity():0;
		}
		return arr;
	}

	public Double[] arrayOfWeightSum() {
		Integer cat = getCategories();
		Double[] arr = (Double[]) Array.newInstance(Double.class, cat);
		for(int i = 0; i < cat; i++ ){
			arr[i] = this.hasInfo(i)?this.getInfo(i).getWeightSum():0d;
		}
		return arr;
	}

	public Integer[][] arrayOfGaps() {
		Integer cat = getCategories();
		Integer[][] arr = new Integer[cat][];
		for(int i = 0; i < cat; i++ ){
			arr[i] = this.hasInfo(i)?this.getInfo(i).arrayOfGaps():new Integer[0];
		}
		return arr;
	}
	
	public Integer[] arrayOfRepeatMarkers(){
		Integer cat = getCategories();
		Integer[] arr = new Integer[cat];
		for(int i = 0; i < cat; i++ ){
			arr[i] = this.hasInfo(i)?this.getInfo(i).getRepeatMarkers():0;
		}
		return arr;		
	}
	
	@Override
	public String toString() {
		return infoArr.toString();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		int cat = getCategories();
		result = prime * result + cat;
		for(int i = 0; i < cat ; ++i){
			CategoryReadInfo ci = this.infoArr.get(i);
			if(null != ci){
				result = prime * result + ci.hashCode();
			} 
		}
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReadWrapper other = (ReadWrapper) obj;
		int cat = getCategories();
		if(!other.getCategories().equals(cat))
			return false;
		for(int i = 0; i < cat; ++i){
			if(hasInfo(i) != other.hasInfo(i))
				return false;
			if(hasInfo(i)){
				if(!getInfo(i).equals(other.getInfo(i))){
					return false;
				}
			}
		}
		return true;
	}
		
	
	
}
